.TITLE DMDRV .IDENT /15.01/ ; ; Copyright (c) 1995-1999 by Mentec, Inc., U.S.A. ; All rights reserved ; ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; PREVIOUSLY MODIFIED BY: ; ; P. J. BEZEREDI ; B. S. MCCARTHY ; G. MARIGOWDA ; M. W. ZAHAREE ; ; MODIFIED FOR RSX-11M-PLUS V4.4 BY: ; ; M. W. ZAHAREE 1-AUG-91 15.01 ; MWZ017 RKWC ALSO IN ERROR WHEN DATA LATE DECLARED ON READ. ; ; ; RK611-RK06/RK07 OVERLAPPED SEEK DISK DRIVER ; .MCALL HWDDF$,PKTDF$ HWDDF$ ;DEFINE HARDWARE REGISTERS PKTDF$ ;DEFINE I/O PACKET OFFSETS ; ; EQUATED SYMBOLS ; RETRY= 8. ;CONTROLLER ERROR RETRY COUNT OFFTRY= 2 ;OFFSET POSITION RETRY COUNT RMCNT= 22. ;NUMBER OF REGISTERS TO LOG ON ERROR RCL= 1 ;RECALIBRATE IN PROGRESS (1=YES) OFS= 2 ;OFFSET IN PROGRESS (1=YES) XCT= 4 ;FUNCTION EXECUTION IN PROGRESS (1=YES) OFM= 10 ;IN OFFSET MODE (1=YES) ADR= 40 ;ADDRESS BITS SETUP (1=YES) ; ; RK611 DEVICE REGISTER OFFSETS ; RKCS1= 0 ;CONTROL STATUS REGISTER 1 RKWC= 2 ;WORD COUNT RKBA= 4 ;BUS ADDRESS RKDA= 6 ;DISK ADDRESS RKCS2= 10 ;CONTROL STATUS REGISTER 2 RKDS= 12 ;DRIVE STATUS RKER= 14 ;ERROR REGISTER RKOF= 16 ;OFFSET/ATTENTION REGISTER RKDC= 20 ;DESIRED CYLINDER RKDB= 24 ;DATA BUFFER RKMR1= 26 ;MAINTENANCE REGISTER 1 RKECPS= 30 ;ECC POSITION RKECPT= 32 ;ECC PATTERN RKMR2= 34 ;MAINTENANCE REGISTER 2 RKMR3= 36 ;MAINTENANCE REGISTER 3 ; ; RKCS1 BIT ASSIGNMENTS ; SD= 1 ;SELECT DRIVE & GET STATUS WRT= 2 ;WRITE OFFSET ACK= 3 ;PACK ACKNOWLEDGE DC= 5 ;DRIVE CLEAR UNL= 7 ;UNLOAD HEADS IE= 100 ;INTERRUPT ENABLE RDY= 200 ;CONTROLLER READY HMS= 113 ;IE + RECALIBRATE + GO OFF= 115 ;IE + OFFSET + GO BLS= 117 ;IE + SEEK + GO READ= 121 ;IE + READ + GO RDH= 125 ;IE + READ HEADER + GO WDH= 127 ;IE + WRITE HEADER + GO WCK= 131 ;IE + WRITE CHECK + GO CERR= 100000 ;CONTROLLER ERROR/CONTROLLER CLEAR DI= 040000 ;DRIVE INTERRUPT DCPAR= 020000 ;DRIVE TO CONTROLLER PARITY ERROR CTO= 004000 ;CONTROLLER TIMEOUT CDT= 002000 ;CONTROLLER DRIVE TYPE ; ; RKCS2 BIT ASSIGNMENTS ; DLT= 100000 ;DATA LATE WCE= 040000 ;WRITE CHECK ERROR UPE= 020000 ;UNIBUS PARITY NED= 010000 ;NON EXISTANT DISK NEM= 004000 ;NON EXISTANT MEMORY PGE= 002000 ;PROGRAMMING ERROR MDS= 001000 ;MULTIPLE DRIVE SELECT UFE= 000400 ;UNIT FIELD ERROR OR= 000200 ;OUTPUT READY (SILO CONTAINS DATA) SCLR= 000040 ;RESET CONTROLLER AND ALL DRIVES RLS= 000010 ;RELEASE PORT ; ; RKDS BIT ASSIGNMENTS ; SVAL= 100000 ;STATUS VALID PIP= 020000 ;POSITIONING IN PROGRESS DDT= 000400 ;DISK DRIVE TYPE DRDY= 000200 ;DRIVE READY VV= 000100 ;VOLUME VALID DRA= 000001 ;DRIVE AVAILABLE ; ; RKER BIT ASSIGNMENTS ; DCK= 100000 ;DATA CHECK ERROR UNS= 040000 ;DRIVE UNSAFE OPI= 020000 ;OPERATION INCOMPLETE DTE= 010000 ;DRIVE TIMING ERROR WLE= 004000 ;WRITE LOCK ERROR IDAE= 002000 ;INVALID DISK ADDRESS COE= 001000 ;CYLINDER OVERFLOW HVRC= 000400 ;HEADER VRC ERROR BSE= 000200 ;BAD SECTOR ERROR ECH= 000100 ;ERROR CORRECTION HARD DTYE= 000040 ;DISK TYPE ERROR FMTE= 000020 ;FORMAT ERROR CDPAR= 000010 ;CONTROLLER TO DRIVE PARITY ERROR NXF= 000004 ;NON-EXECUTABLE FUNCTION SKI= 000002 ;SEEK INCOMPLETE ILF= 000001 ;ILLEGAL FUNCTION ; ; LOCAL DATA ; ; CONTROLLER IMPURE DATA TABLES ; THESE ARE INDEXED BY THE CONTROLLER NUMBER ; RTTBL: .BLKW R$$611 ;RETRY COUNT FOR CURRENT OPERATION OFFRTY: .BLKW R$$611 ;OFFSET RECOVERY RETRY COUNTS RGBLK: .BLKW R$$611*RMCNT ;CONTROLLER REGISTER STORAGE AREA OFFAD: .BLKW R$$611 ;ADDRESS OF CURRENT OFFSET VALUE PRMSV: .BLKW R$$611*5 ;PARAMETER SAVE ARE FOR ERROR RECOVERY ;AND WRITE CHECK FUNCTION $DMOPT::.REPT R$$611 ;SEEK OPTIMIZATION TABLE .WORD 1 ;0=IMPLIED SEEK; 1=ALWAYS SEEK FIRST .ENDR SILOA: .BLKW R$$611 ;TABLE OF CURRENT SILO ADJUSTMENTS ; ; DIAGNOSTIC FUNCTION TABLE ; FUNTBL: .BYTE HMS, IO.HMS!IQ.UMD&377 .BYTE BLS, IO.BLS!IQ.UMD&377 .BYTE OFF, IO.OFF!IQ.UMD&377 .BYTE RDH, IO.RDH!IQ.UMD&377 .BYTE WDH, IO.WDH!IQ.UMD&377 .BYTE WCK, IO.WCK!IQ.UMD&377 FUNTBE: ; ; OFFSET POSITIONING DATA ; OFFTB: ;POSITIONING VALUE TABLE .BYTE 000 ;RETURN TO CENTERLINE .BYTE 020 ; +400 .BYTE 220 ; -400 .BYTE 040 ; +800 .BYTE 240 ; -800 .BYTE 060 ; +1200 .BYTE 260 ; -1200 OFFTBE: .BYTE 000 ;RETURN TO CENTERLINE ; ;DRIVER DISPATCH TABLE ; DDT$ DM,R$$611,,,,,,OPT ;GENERATE DISPATCH TABLE ;+ ; **-DMINI-RK611-RK06/RK07 DISK CARTRIDGE CONTROLLER INITIATOR ; ; THIS IS THE DRIVER ENTRY POINT FROM THE QUEUE I/O DIRECTIVE WHEN AN ; I/O REQUEST IS QUEUED AND AT THE END OF A PREVIOUS I/O OPERATION TO ; PROPAGATE THE EXECUTION OF THE DRIVER. IF THE SPECIFIED UNIT IS NOT ; BUSY, THEN AN ATTEMPT IS MADE TO DEQUEUE THE NEXT I/O REQUEST. ELSE ; A RETURN TO THE CALLER IS EXECUTED. IF THE DEQUEUE ATTEMPT SUCCEEDS, ; THEN THE NEXT I/O OPERATION IS INITIATED AND A RETURN TO THE CALLER ; IS EXECUTED. ; ; INPUTS: ; ; R5=ADDRESS OF THE UCB OF THE UNIT TO BE INITIALIZED. ; ; OUTPUTS: ; ; IF THE SPECIFIED UNIT IS NOT BUSY AND AN I/O REQUEST IS WAITING ; TO BE PROCESSED, THEN THE REQUEST IS DEQUEUED AND THE I/O OPER- ; ATION IS INITIATED. ;- DMINI: GTPKT$ DM,R$$611 ;GET NEXT I/O PACKET TO PROCESS ; ; THE FOLLOWING ARGUMENTS ARE RETURNED BY $GTPKT: ; ; R1=ADDRESS OF THE I/O REQUEST PACKET. ; R2=PHYSICAL UNIT NUMBER OF THE REQUEST UCB. ; R3=CONTROLLER INDEX. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UCB OF THE UNIT TO BE INITIALIZED. ; ; RK611-RK06/RK07 DISK CARTRIDGE I/O REQUEST PACKET FORMAT: ; ; WD. 00 -- I/O QUEUE THREAD WORD ; WD. 01 -- REQUEST PRIORITY, EVENT FLAG NUMBER ; WD. 02 -- ADDRESS OF THE TCB OF THE REQUESTOR TASK ; WD. 03 -- POINTER TO 2ND LUN WORD IN REQUESTOR TASK HEADER ; WD. 04 -- CONTENTS OF FIRST LUN WORD (UCB ADDRESS) ; WD. 05 -- I/O FUNCTION CODE ; WD. 06 -- VIRTUAL ADDRESS OF I/O STATUS BLOCK ; WD. 07 -- RELOCATION BIAS OF I/O STATUS BLOCK ; WD. 10 -- I/O STATUS BLOCK ADDRESS (DISPLACEMENT + 140000) ; WD. 11 -- VIRTUAL ADDRESS OF AST SERVICE ROUTINE ; WD. 12 -- MEMORY EXTENSION BITS OF I/O TRANSFER ; WD. 13 -- BUFFER ADDRESS OF I/O TRANSFER ; WD. 14 -- NUMBER OF BYTES TO BE TRANSFERED ; WD. 15 -- DIAGNOSTIC SUPPLIMENTAL PARAMETER ELSE NOT USED ; WD. 16 -- BITS <0:7> = HIGH LBN, BITS <8:15> NOT USED ; WD. 17 -- LOW LBN OF I/O REQUEST ; WD. 20 -- RELOCATION BIAS OF DIAGNOSTIC REGISTER BLOCK ; WD. 21 -- DIAGNOSTIC REGISTER BLOCK ADDRESS DISPLACEMENT ; CLRB U.CW2+1(R5) ;RESET UNIT FLAGS CALL $VOLVD ;VALIDATE VOLUME VALID BCS 10$ ;IF CS WE FAILED TST R0 ;TRANSFER FUNCTION? BMI DMRQC ;IF MI YES JMP DMVV ;PROCESS VOLUME VALID FUNCTION 10$: JMP DMDONE ;EXIT ; ; REQUEST CONTROLLER FOR PROPER OPERATION ; DMRQC: MOV S.KRB(R4),R1 ;GET CURRENT KRB ADDRESS BIT #KS.POE,K.STS(R1) ;PARALLEL OPERATIONS ENABLED? BEQ DMRQC1 ;IF EQ NO MOV S.PKT(R4),R3 ;RETRIEVE I/O PACKET ADDRESS BITB #IQ.UMD!IQ.Q,I.FCN(R3) ;DIAGNOSTIC OR EXPRESS REQUEST? BNE DMRQC1 ;IF NE YES MOVB K.CON(R1),R3 ;RETREIVE CONTROLLER INDEX TST $DMOPT(R3) ;WHICH SEEK METHOD? BNE 10$ ;IF NE ALWAYS SEEK FIRST BIT #KS.DIP,K.STS(R1) ;DATA TRANSFER IN PROGRESS? BEQ DMRQC1 ;IF EQ NO, START DATA TRANSFER 10$: BISB #S3.SIP,S.ST3(R4) ;SET SEEK IN PROGRESS CALL $RQCNC ;REQUEST CONTROLLER FOR CONTROL FUNCTION BR DMINIO ;INITIATE THE SEEK DMRQC1: BICB #S3.SIP,S.ST3(R4) ;SET SEEK ALREADY COMPLETED CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER ; ; **-DMUBMP-SETUP UNIBUS ADDRESS ; ; THIS SECTION OF CODE WILL DETERMINE IF THE UNIBUS ADDRESS IS ; ALREADY IN THE FORMAT FOR THE UNIBUS MAP ON 22-BIT PROCESSORS. ; IT WILL ALSO CONVERT THE I/O FUNCTION CODE TO IT'S HARDWARE ; EQUIVALENT. ; ; NOTE: AT THIS POINT THE REQUESTING UNIT MUST BE THE OWNER OF ; THE CONTROLLER FOR A DATA TRANSFER. ; DMUBMP: BITB #ADR,U.CW2+1(R5);ADDRESS BITS ALREADY SETUP? BNE DMINIO ;IF NE YES MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS CMP #IO.RDH!IQ.UMD,I.FCN(R1) ;READ HEADER FUNCTION? BEQ 10$ ;IF EQ YES, NO NEED FOR UMR'S CALL $STMAP ;SETUP UNIBUS MAP ADDRESS 10$: ASL U.BUF(R5) ;POSITION MEMORY EXTENSION BITS ASL U.BUF(R5) ;... ASL U.BUF(R5) ;... ASL U.BUF(R5) ;... CMP #IO.RDH!IQ.UMD,I.FCN(R1) ;READ HEADER FUNCTION? BEQ 20$ ;IF EQ YES, NO NEED FOR UMR'S CALL $MPUBM ;MAP UNIBUS TO TRANSFER 20$: BISB #ADR,U.CW2+1(R5);INDICATE ADDRESS SETUP COMPLETE ; ; CONVERT I/O FUNCTION CODE TO HARDWARE EQUIVALENT. ; MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS CMPB #IO.HMS/256.,I.FCN+1(R1) ;DIAGNOSTIC FUNCTION? BNE 40$ ;IF NE NO MOV #FUNTBL,R0 ;GET ADDRESS OF FUNCTION TABLE 30$: MOVB (R0)+,U.BUF(R5) ;LOAD CONTROLLER FUNCTION CODE CMPB (R0)+,I.FCN(R1) ;IS IT THE CORRECT CODE? BEQ 60$ ;IF EQ YES CMP #FUNTBE,R0 ;END OF FUNCTION TABLE? BNE 30$ ;IF NE NO 40$: MOV #IE.IFC&377,R0 ;ASSUME ILLEGAL FUNCTION MOVB #READ,U.BUF(R5) ;ASSUME READ FUNCTION CMPB #IO.RLB/256.,I.FCN+1(R1) ;READ LOGICAL FUNCTION? BHIS 50$ ;IF HIS FUNCTION IS ILLEGAL MOV @S.KRB(R4),R2 ;RETREIVE CSR ADDRESS CALL DMSDC ;SELECT THE DRIVE JMP DMFIN1 ;FINISH I/O 50$: BEQ 60$ ;IF EQ YES ADD #WRT,U.BUF(R5) ;CONVERT TO WRITE FUNCTION 60$: MOV S.KRB(R4),R3 ;RETRIEVE KRB ADDRESS MOVB K.CON(R3),R3 ;RETRIEVE CONTROLLER INDEX MUL #5,R3 ;SETUP AN INDEX INTO ... ADD #PRMSV,R3 ;... PARAMETER SAVE AREA MOV U.BUF(R5),(R3)+ ;SAVE PARAMETERS MOV U.BUF+2(R5),(R3)+ ;... MOV U.CNT(R5),(R3)+ ;... MOV I.PRM+10(R1),(R3)+ ;... MOV I.PRM+12(R1),(R3)+ ;... ; ; **-DMINIO-INITIATE AN I/O OPERATION ; ; THIS ROUTINE WILL INITIATE EITHER A SEEK OR THE DATA TRANSFER ; OPERATION DEPENDING ON HOW THE CONTROLLER WAS REQUESTED. ; ; INPUTS: ; ; R4=ADDRESS OF THE SCB. ; R5=ADDRESS OF THE UCB. ; DMINIO: BICB #RCL!OFS,U.CW2+1(R5) ;RESET POSITIONING FLAGS MOV @S.KRB(R4),R2 ;GET CSR ADDRESS MOV S.PKT(R4),R3 ;RETREIVE I/O PACKET ADDRESS MOV #CERR,(R2) ;CLEAR THE CONTROLLER MOVB U.UNIT(R5),R0 ;FETCH UNIT NUMBER MOV R0,RKCS2(R2) ;SELECT THE DRIVE ; ; DETERMINE IF DRIVE'S PORT IS SEIZED BY THIS CONTROLLER. ; CALL DMSD ;ATTEMPT TO SEIZE THE DRIVE BIT #DRA,RKDS(R2) ;DID WE SEIZE THE DRIVE? BNE 10$ ;IF NE YES CALL DMCLR ;CLEAR THE CONTROLLER ERROR MOV #IE.DNR&377,R0 ;SET DRIVE NOT READY ERROR CODE BR 40$ ;AND GO AWAY ; ; CHECK IF THE HEADS ARE ON THE CORRECT CYLINDER. ; 10$: CALL DMCLER ;CLEAR CONTROLLER AND DRIVE BITB #S3.SIP,S.ST3(R4) ;ARE WE DOING A SEEK? BEQ 20$ ;IF EQ NO CALL DMCYL ;GET CURRENT CYLINDER ADDRESS CMP I.PRM+10(R3),R0 ;DO WE NEED TO SEEK? BNE 30$ ;IF NE YES, BYPASS CONTROLLER SETUP MOV #IE,(R2) ;RE-ENABLE INTERRUPTS JMP DMRQC1 ;GO REQUEST CONTROLLER ; ; LOAD CONTROLLER REGISTERS FOR DATA TRANSFER. ; 20$: ADD #RKCS2,R2 ;POINT TO RKCS2 MOV I.PRM+12(R3),-(R2) ;SET TRACK AND SECTOR ADDRESS MOV U.BUF+2(R5),-(R2) ;SET USER BUFFER ADDRESS MOV U.CNT(R5),-(R2) ;SET BYTES TO TRANSFER ROR (R2) ;MAKE THAT WORDS TO TRANSFER NEG (R2) ;MAKE IT A NEGATIVE WORD COUNT TST -(R2) ;POINT TO CSR ; ; CHECK FOR DRIVE NOT READY CONDITIONS. ; 30$: CALL DMDC ;CLEAR DRIVE MOV #IE.DNR&377,R0 ;ASSUME SELECTED UNIT NOT READY MOV I.PRM+10(R3),RKDC(R2) ;SET CYLINDER ADDRESS MOV RKDS(R2),R1 ;GET CURRENT DRIVE STATUS COM R1 ;COMPLEMENT STATUS BIT #SVAL!DRDY!DRA,R1 ;DRIVE READY? BNE 40$ ;IF NE NO BIT #UNS,RKER(R2) ;DRIVE UNSAFE? BEQ 60$ ;IF EQ NO 40$: BITB #US.SPU,U.STS(R5) ;IS DRIVE SPINNING UP? BEQ 45$ ;IF EQ NO BITB #US.VV,U.STS(R5);WAS THE VOLUME PREVIOUSLY MOUNTED? BEQ DMPWF1 ;IF EQ NO BR DMPWF0 ;YES, WAIT FOR IT TO SPIN UP 45$: MOV R3,R1 ;COPY I/O PACKET ADDRESS CALL DMDINT ;TRY FOR DIAGNOSTIC DRIVE NOT READY BCS 50$ ;IF CS IT WAS .IF DF S2.NRD BIT #S2.NRD,S.ST2(R4) ;IS THIS FIRST DRIVE NOT READY? BNE 47$ ;IF NE NO, GO LOG ERROR BIS #S2.NRD,S.ST2(R4) ;INDICATE FIRST DRIVE NOT READY JMP DMPWF1 ;GO DO A RETRY 47$: BIC #S2.NRD,S.ST2(R4) ;CLEAR FIRST DRIVE NOT READY .ENDC ; DF S2.NRD CALL DMLERR ;LOG DRIVE NOT READY ERROR 50$: JMP DMFIN ;FINISH I/O 60$: BIT #VV,R1 ;DID VOLUME VALID CHANGE? BEQ 65$ ;IF EQ NO (NOTE REVERSE STATUS OF VV) BITB #US.SPU,U.STS(R5) ;DID WE JUST SPIN UP? BEQ 40$ ;IF EQ NO MOV #ACK,R0 ;GET PACK ACKNOWLEDGE FUNCTION CALL DMGO ;SET VV BISB #US.VV,U.STS(R5);SET SOFTWARE VOLUME VALID 65$: BIT #S2.MAD,S.ST2(R4) ;MULTI ACCESS DEVICE? BEQ 80$ ;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;IS THIS PORT 'A'? BNE 70$ ;IF NE NO BICB #S3.SPA,S.ST3(R4) ;YES, SHOW IT SPUN UP BR 75$ ; 70$: BICB #S3.SPB,S.ST3(R4) ;IT MUST BE PORT 'B' 75$: BITB #S3.SPU,S.ST3(R4) ;BOTH PORTS SPUN UP? BNE 85$ ;IF NE NO 80$: BICB #US.SPU,U.STS(R5) ;RESET DRIVE SPINNING UP 85$: BITB #S3.SIP,S.ST3(R4) ;SHOULD WE DO A SEEK? BEQ 90$ ;IF EQ NO ; ; START EXPLICIT SEEK. ; MOV #BLS,R0 ;GET SEEK FUNCTION CODE CALL DMXFR ;START THE SEEK BR DMPWF3 ;RELEASE CONTROLLER AND EXIT ; ; START DATA TRANSFER. ; 90$: CMPB U.BUF(R5),#BLS ;IS THIS A POSITIONING FUNCTION? BHI DMDIP ;IF HI NO BISB #RCL!OFS,U.CW2+1(R5) ;SET POSITIONING FLAGS CMP #IO.OFF!IQ.UMD,I.FCN(R3) ;OFFSET FUNCTION? BNE DMDIP ;IF NE NO MOV I.PRM+6(R3),RKOF(R2) ;YES, SET OFFSET VALUE DMDIP: MOV U.BUF(R5),R0 ;GET FUNCTION CODE AND MEMORY BITS DMDIP1: MTPS #PR5 ;;;EXECUTE AT DEVICE PRIORITY MOV S.KRB(R4),R3 ;;;GET KRB ADDRESS BIT #IQ.UMD,I.FCN(R1) ;;;IS IT A DIAGNOSTIC FUNCTION? BEQ DMDIP2 ;;;IF EQ NO CMPB U.BUF(R5),#BLS ;;;IS IT A UMD SEEK FUNCTION? BLOS DMXFR ;;;IF LOS YES DMDIP2: BIS #KS.DIP,K.STS(R3) ;;;SET DATA TRANSFER IN PROGRESS DMXFR: MTPS #PR5 ;;;DISABLE INTERRUPTS CLR S.FRK+2(R4) ;;;INIT FORK INTERLOCK BIS #S2.ACT,S.ST2(R4) ;;;SHOW I/O IS ACTIVE BISB #XCT,U.CW2+1(R5) ;;;SHOW FUNCTION HAS EXECUTED MOVB S.ITM(R4),S.CTM(R4) ;;;SET TIMEOUT COUNT CALL DMXCT ;;;SET CDT,LOAD FUNCTION AND GO MTPS #0 ;ALLOW INTERRUPTS ;+ ; CANCEL I/O OPERATION IS A NOP FOR FILE STRUCTURED DEVICES. ;- DMCAN: RETURN ;;;NOP FOR THE RK611 ;+ ; POWERFAIL IS HANDLED VIA THE DEVICE TIMEOUT FACILITY AND ; CAUSES NO IMMEDIATE ACTION ON THE UNIT. THE CURRENT TIMEOUT ; COUNT IS EXTENDED SO THAT IF THE UNIT WAS BUSY IT WILL HAVE ; SUFFICIENT TIME TO SPIN BACK UP. THE NEXT I/O REQUEST TO ANY ; UNIT WILL BE SUSPENDED FOR AT LEAST THE EXTENDED TIMEOUT UNLESS ; THE UNIT IS ALREADY READY. ;- DMPWF: MOV @S.KRB(R4),R2 ;GET CSR ADDRESS CALL DMCLR ;CLEAR THE CONTROLLER TSTB S.STS(R4) ;IS DRIVE CURRENTLY BUSY? BEQ DMPWF2 ;IF EQ NO DMPWF0: MOVB #15.,S.STS(R4) ;WAIT A MAXIMUM OF ONE MINUTE DMPWF1: MOVB S.ITM(R4),S.CTM(R4) ;4 SECONDS AT A TIME DMPWF2: BISB #US.SPU,U.STS(R5) ;SET UNIT SPINNING UP DMPWF3: CALLR $RLCN ;RELEASE CONTROLLER IF NECESSARY ;+ ; **-$DMINT-RK611-RK06/RK07 DISK CARTRIDGE CONTROLLER ; INTERRUPT AND ERROR SERVICE ROUTINES ; ; HARD ERRORS ---> $IODON ; SOFT ERRORS ---> RETRY LAST FUNCTION ; DATA ERRORS ---> RETRY FUNCTION AND CORRECT IF POSSIBLE ;- .ENABL LSB $DMINT::BR DMFRK ;;;ENTRY POINT FOR DATA TRANSFERS TST S.FRK+2(R4) ;;;UNSOLICITED INTERRUPT? BEQ 5$ ;;;IF EQ NO MOV @S.KRB(R4),-(SP);;;RETREIVE CSR ADDRESS BIC #IE!CERR,(SP)+ ;;;DISABLE INTERRUPTS RETURN ;;; 5$: CALL $FORK ;;;CREATE A SYSTEM PROCESS DMFRK: CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV S.KRB(R4),R3 ;GET CURRENT KRB ADDRESS MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX MOV @S.KRB(R4),R2 ;GET CSR ADDRESS MOVB U.UNIT(R5),R0 ;GET UNIT TO SELECT MOV R0,RKCS2(R2) ;SELECT THE UNIT TSTB S.STS(R4) ;IS THIS UNIT BUSY? BNE 10$ ;IF NE YES CALL DMSDC ;SELECT THE DRIVE CALL DMDC ;CLEAR DRIVE (DROPS ATA) BIS #RLS,RKCS2(R2) ;SET TO RELEASE THE PORT CALL DMSD ;RELEASE THE PORT BISB #S3.DRL,S.ST3(R4) ;SHOW DUAL ACCESS UNIT RELEASED CLR S.FRK+2(R4) ;RESET FORK INTERLOCK MOV #IE,(R2) ;RE-ENABLE INTERRUPTS BR DMPWF3 ;RELEASE CONTROLLER AND EXIT ; ; INTERRUPT WAS FROM A BUSY UNIT. IF WE JUST DID A SEEK WE WILL ; GO AND START THE DATA TRANSFER OPERATION. IF THE DATA TRANSFER ; TERMINATED, DETERMINE WHY. IF WE ARE SPINNING UP, RETRY THE ; OPERATION. ; 10$: BITB #US.SPU,U.STS(R5) ;ARE WE SPINNING UP? BEQ 15$ ;IF EQ NO BIT #S2.MAD,S.ST2(R4) ;MULTI-ACCESS DEVICE? BEQ DMREST ;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;IS THIS PORT 'A'? BNE 14$ ;IF NE NO BITB #S3.SPA,S.ST3(R4) ;IS PORT 'A' SPINNING UP? BNE DMREST ;IF NE YES BR 15$ ; 14$: BITB #S3.SPB,S.ST3(R4) ;IS PORT 'B' SPINNING UP? BNE DMREST ;IF NE YES 15$: MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS BIT #S2.EIP,S.ST2(R4) ;ERROR ALREADY IN PROGRESS? BNE 20$ ;IF NE YES CALL DMPRM ;RESET RETRY AND OFFSET RECOVERY VALUES 20$: BITB #S3.SIP,S.ST3(R4) ;DID WE JUST DO A SEEK? BEQ 30$ ;IF EQ NO BICB #S3.SIP,S.ST3(R4) ;CLEAR SEEK IN PROGRESS TST (R2) ;ANY ERRORS DURING THE SEEK? BPL 70$ ;IF PL NO CALL DMSDC ;ISSUE SELECT DRIVE FUNCTION CALL DMLERR ;LOG THE SEEK ERROR MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS DECB RTTBL(R3) ;COUNT THIS RETRY CALL DMERL ;FINISH ERROR LOGGING CALLR DMRCAL ;ISSUE RECALIBRATE FUNCTION ; ; VALID INTERRUPT. ; 30$: MOV #IS.SUC&377,R0 ;ASSUME SUCCESSFUL TRANSFER CALL DMDINT ;PROCESS DIAGNOSTIC INTERRUPT BCS 100$ ;IF CS INTERRUPT PROCESSING COMPLETE BITB #RCL!OFS,U.CW2+1(R5) ;POSITIONING FUNCTION? BNE 40$ ;IF NE YES ; ; INTERRUPT WAS DUE TO A DATA TRANSFER OPERATION. ; TST (R2) ;ANY ERRORS? BMI 35$ ;IF MI YES, FORGET STATUS UPDATE TST RKDS(R2) ;IS THE CURRENT STATUS VALID? BMI 35$ ;IF MI YES CALL DMSDC ;ISSUE SELECT DRIVE FUNCTION 35$: TST (R2) ;ANY ERRORS? BPL DMWCHK ;IF PL NO CALL DMLERR ;YES, LOG THE DEVICE ERROR MOV RKER(R2),R1 ;COPY CONTENTS OF ERROR REGISTER MOV #IE.WLK&377,R0 ;ASSUME WRITE LOCK ERROR BIT #WLE,R1 ;WRITE LOCK ERROR? BNE 50$ ;IF NE YES MOV #IE.BBE&377,R0 ;ASSUME BAD BLOCK ERROR BIT #BSE,R1 ;BAD BLOCK ERROR? BNE 50$ ;IF NE YES MOV #IE.VER&377,R0 ;ASSUME UNRECOVERABLE ERROR BIT #UNS!DTE!IDAE!COE!DTYE!FMTE!NXF!ILF,R1 ;HARD ERROR? BNE 50$ ;IF NE YES BIT #UPE!NED!NEM!PGE!MDS!UFE,RKCS2(R2) ;HARD ERROR? BNE 50$ ;IF NE YES, FINISH UP JMP DMSOFT ;TRY FOR SOFT/DATA ERRORS ; ; ; PROCESS POSITIONING OPERATION ; 40$: MOVB U.CW2+1(R5),R0 ;GET UNIT FLAGS COM R0 ;TOGGLE THEM BIT #OFM!RCL,R0 ;IN OFFSET MODE AND DOING A RECAL? BNE 45$ ;IF NE NO CLR R0 ;GET READY FOR THE BISB BISB RTTBL+1(R3),R0 ;RETREIVE ERROR/SUCCESS CODE BICB #OFM!RCL,U.CW2+1(R5) ;CLEAR FLAGS CALLR DMFIN1 ;NOW SAY GOOD-BYE 45$: MOV #IE.VER&377,R0 ;ASSUME UNRECOVERABLE ERROR TST (R2) ;ERRORS DURING POSITIONING? BPL 60$ ;IF PL NO CLR RKWC(R2) ;SHOW ALL BYTES TRANSFERED 50$: JMP DMFIN ;FINISH I/O 60$: BITB #RCL,U.CW2+1(R5);RECALIBRATE FUNCTION? BEQ 65$ ;IF EQ NO JMP DMRTRY ;YES, RETRY PREVIOUS FUNCTION 65$: BICB #OFS,U.CW2+1(R5) ;RESET OFFSET FLAG CMP #OFFTBE,OFFAD(R3) ;FINAL OFFSET TRIED? BEQ 50$ ;IF EQ YES ; ; RESTART THE I/O OPERATION ; DMREST: MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS 70$: JMP DMUBMP ;SETUP UNIBUS MAP AND RETRY FUNCTION ; ; TEST FOR WRITE CHECK OPERATION ; DMWCHK: MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS BITB #IO.WLC&377,I.FCN(R1) ;WRITE FOLLOWED BY WRITE CHECK? BNE 80$ ;IF NE YES BITB #US.WCK,U.STS(R5) ;WRITE CHECK ENABLED BY MCR? BEQ 100$ ;IF EQ NO 80$: CMPB #READ,U.BUF(R5) ;WAS LAST FUNCTION A READ? BEQ 100$ ;IF EQ YES CMPB #READ+WRT,U.BUF(R5) ;WAS LAST FUNCTION A WRITE? BNE 100$ ;IF NE NO CALL DMPRM ;RESET RETRY COUNT MUL #5,R3 ;FORM AN INDEX INTO ... ADD #PRMSV,R3 ;... PARAMETER SAVE AREA MOV (R3)+,U.BUF(R5) ;RESTORE PARAMETERS MOV (R3)+,U.BUF+2(R5) ;... MOV (R3)+,U.CNT(R5) ;... MOV (R3)+,I.PRM+10(R1) ;... MOV (R3)+,I.PRM+12(R1) ;... MOVB #WCK,U.BUF(R5) ;SET WRITE CHECK FUNCTION BR DMREST ;START WRITE CHECK OPERATION 100$: CLR U.CNT(R5) ;NO ERRORS, SET ALL BYTES TRANSFERED BR DMFIN1 ;FINISH I/O .DSABL LSB ;+ ; DEVICE TIMEOUT RESULTS IN THE CURRENT OPERATION BEING REPEATED ; UNLESS THE OPERATION WAS DIAGNOSTIC. TIMEOUTS ARE USUALLY CAUSED ; BY POWER FAILURE BUT MAY ALSO BE THE RESULT OF NO RESPONSE ; FROM THE HARDWARE. ;- DMOUT: BITB #US.SPU,U.STS(R5) ;;;IS DRIVE SPINNING UP? BEQ 15$ ;;;IF EQ NO BIT #S2.MAD,S.ST2(R4) ;;;MULTI-ACCESS DEVICE? BEQ 10$ ;;;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;;;IS THIS PORT 'A'? BNE 5$ ;;;IF NE NO, IT MUST BE PORT 'B' BITB #S3.SPA,S.ST3(R4) ;;;IS PORT 'A' SPINNING UP? BNE 10$ ;;;IF NE YES BR 15$ ;;;TIMEOUT FOR NORMAL FUNCTION 5$: BITB #S3.SPB,S.ST3(R4) ;;;IS PORT 'B' SPINNING UP? BEQ 15$ ;;;IF EQ NO, NORMAL FUNCTION 10$: DECB S.STS(R4) ;;;HAVE WE WAITED ENOUGH YET? BEQ 15$ ;;;IF EQ YES MTPS #0 ;;;ALLOW INTERRUPTS JMP DMRQC ;REQUEST CONTROLLER AND RESTART I/O 15$: INCB S.STS(R4) ;;;LEAVE CONTROLLER BUSY MOV S.PKT(R4),R1 ;;;GET I/O PACKET ADDRESS MOV (R2),I.PRM+6(R1);;;SAVE CSR CONTENTS MTPS #0 ;;;ALLOW INTERRUPTS CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV #IE.DNR&377,R0 ;GET DEVICE NOT READY ERROR CODE MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS MOV I.PRM+6(R1),$DVSAV ;SAVE SAVED CSR CONTENTS MOV S.KRB(R4),R2 ;GET CURRENT KRB ADDRESS MOVB K.CON(R2),R3 ;RETREIVE CONTROLLER INDEX MOV (R2),R2 ;GET CSR ADDRESS MOVB U.UNIT(R5),R1 ;GET UNIT TO SELECT MOV R1,RKCS2(R2) ;SELECT THE UNIT CALL DMSDC ;ISSUE SELECT DRIVE FUNCTION MOV S.PKT(R4),R1 ;PUT BACK THE I/O PKT ADDRESS CALL DMDINT ;TEST FOR DIAGNOSTIC TIMEOUT BCS DMFIN ;IF CS IT WAS CALL DMLTMO ;LOG DEVICE TIMEOUT BITB #S3.SIP,S.ST3(R4) ;TIMEOUT DURING A SEEK? BEQ 20$ ;IF EQ NO CALL DMPRM ;RESET RETRY AND OFFSET RECOVERY VALUES 20$: BICB #S3.SIP,S.ST3(R4) ;ASSUME DATA TRANSFER FUNCTION BICB #OFM,U.CW2+1(R5);CLEAR OFFSET MODE FLAG BITB #RCL!OFS,U.CW2+1(R5) ;TIMEOUT DURING POSITIONING? BNE DMFIN ;IF NE YES BITB #US.SPU,U.STS(R5) ;WAS THE DRIVE SPINNING UP? BEQ DMRTRY ;IF EQ NO MOV #IE.DNR&377,R0 ;YES, SET DRIVE NOT READY BR DMFIN ;AND EXIT ; ; CHECK FOR RETRY OF CURRENT FUNCTION ; DMRTRY: MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS BITB #IQ.X,I.FCN(R1) ;INHIBIT RETRIES? BNE DMFIN ;IF NE YES DECB RTTBL(R3) ;RETRY FUNCTION? BLE DMFIN ;IF LE NO JMP DMREST ;YES, RETRY FUNCTION ; ; **-DMFIN-FINISH I/O OPERATION ; ; THIS ROUTINE WILL SET THE ACTUAL BYTES TRANSFERED PARAMETER, THE ; ERROR LOGGING RETRY COUNTS AND CALL $IODON. THE SELECTED DRIVE ; IS RELEASED, IF REQUESTED, AND THE CONTROLLER IS RELEASED. ; ; INPUTS: ; ; R0=SUCCESS/ERROR CODE ; R2=ADDRESS OF CONTROLLER CSR OR REGISTER BLOCK ; R4=ADDRESS OF THE SCB ; R5=ADDRESS OF THE UCB ; DMFIN: MOV RKWC(R2),R1 ;GET RESIDUAL WORD COUNT ASL R1 ;CONVERT TO BYTE COUNT NEG R1 ;CONVERT TO POSITIVE BYTES REMAINING DMFIN0: MOV R1,U.CNT(R5) ;SAVE BYTES REMAINING TO TRANSFER DMFIN1: MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS CALL DMDC ;CLEAR DRIVE DMFIN3: MOV S.KRB(R4),R3 ;RETREIVE KRB ADDRESS MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX BITB #OFM,U.CW2+1(R5);IN OFFSET MODE? BEQ 5$ ;IF EQ NO MOVB R0,RTTBL+1(R3) ;SAVE ERROR/SUCCESS CODE BR DMRCAL ;NOW DO A RECALIBRATE 5$: BITB #S3.NRL,S.ST3(R4) ;SHOULD WE RELEASE THE DRIVE? BNE 15$ ; IF NE NO BIT #DRA,RKDS(R2) ;HAVE WE SEIZED THE DRIVE? BEQ 10$ ;IF EQ NO BIS #RLS,RKCS2(R2) ;RELEASE THE PORT CALL DMSD ;ISSUE SELECT FUNCTION TO RELEASE PORT 10$: BISB #S3.DRL,S.ST3(R4) ;SHOW DUAL ACCESS UNIT RELEASED 15$: MOV #IE,(R2) ;RE-DISPATCH IF DRIVE INTERRUPT SET MOVB RTTBL(R3),R2 ;GET FINAL ERROR RETRY COUNT BITB #XCT,U.CW2+1(R5) ;HAS A FUNCTION BEEN EXECUTED? BNE 20$ ;IF NE YES MOV #RETRY,R2 ;SET MAXIMUM RETRY COUNT 20$: BIS #RETRY*256.,R2 ;MERGE STARTING RETRY COUNT BICB #S3.SIP,S.ST3(R4) ;RESET SEEK IN PROGRESS FLAG CALL $RLCN ;RELEASE CONTROLLER DMDONE: MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS MOV I.PRM+4(R1),R1 ;GET ACTUAL BYTES TO TRANSFER SUB U.CNT(R5),R1 ;CALCULATE BYTES ACTUALLY TRANSFERED CLR S.FRK+2(R4) ;CLEAR THE FORK INTERLOCK FLAG MOV @S.KRB(R4),-(SP) ;GET THE CSR ADDRESS MOV #IE,(SP)+ ;ENABLE INTERRUPTS CALL $IODON ;FINISH I/O OPERATION JMP DMINI ;PROCESS NEXT REQUEST ; ; **-DMSOFT-TEST FOR SOFT RECOVERABLE ERROR CONDITIONS ; ; INPUTS: ; ; R0=IE.VER&377 ; R1=CONTENTS OF RKER ; R2=ADDRESS OF CSR ; DMSOFT: BIT #WCE,RKCS2(R2) ;WRITE CHECK ERROR? BEQ 10$ ;IF EQ NO MOV #IE.WCK&377,R0 ;SET WRITE CHECK ERROR CODE BR DMRTRY ;AND ATTEMPT TO RETRY OPERATION 10$: TST RKCS2(R2) ;DATA LATE ERROR? BMI DMDLT ;IF MI YES BIT #DCPAR!CTO,(R2) ;CONTROLLER TIMEOUT OR PARITY ERROR? BNE DMRTRY ;IF NE YES BIT #CDPAR,R1 ;CONTROLLER TO DRIVE PARITY ERROR? BNE DMRTRY ;IF NE YES BIT #OPI!SKI,R1 ;DRIVE POSITIONING ERROR? BEQ DMECC ;IF EQ NO MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS CALL DMCLER ;CLEAR CONTROLLER AND DRIVE ; ; DO A RECALIBRATE OPERATION ; DMRCAL: MOV #HMS,R0 ;SET RECALIBRATE FUNCTION BISB #RCL,U.CW2+1(R5);INDICATE RECALIBRATE FUNCTION CALLR DMDIP1 ;ISSUE THE RECALIBRATE ; ; **-DMECC-ATTEMPT ECC CORRECTION ; ; THIS ROUTINE IS ENTERED IF A DATA ERROR IS DETECTED. IF THE ERROR ; IS CORRECTABLE, THE EXECUTIVE ECC ROUTINE IS CALLED AND THE OPERATION ; IS RESTARTED FROM WHERE THE CONTROLLER STOPPED. IF OFFSET RECOVERY ; IS REQUIRED, WE WILL DO IT. ; ; INPUTS: ; ; R1=CONTENTS OF RKER ; R2=ADDRESS OF CONTROLLER CSR ; DMECC: CMPB #READ,U.BUF(R5) ;IS THIS A READ OPERATION? BNE DMRTRY ;IF NE NO MOV S.PKT(R4),R3 ;RETREIVE I/O PACKET ADDRESS BITB #IQ.X,I.FCN(R3) ;INHIBIT RETRIES? BNE DMFIN ;IF NE YES MOV S.KRB(R4),R3 ;RETREIVE KRB ADDRESS MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX DECB RTTBL(R3) ;RE-READ THE DATA? BLE 10$ ;IF LE NO, DO THE ECC CORRECTION CALLR DMREST ;YES, RESTART THE TRANSFER 10$: MOVB #RETRY,RTTBL(R3);RESET RETRY COUNT MOV RKWC(R2),R0 ;GET NEGATIVE # OF WORDS REMAINING ASL R0 ;CONVERT TO BYTES ADD U.CNT(R5),R0 ;CALCULATE BYTES ACTUALLY TRANSFERED BEQ DMOFF ;IF EQ NONE TRANSFERED, TRY OFFSET BIC #^C,R1 ;ISOLATE IMPORTANT BITS CMP #DCK,R1 ;ONLY DATA CHECK ERROR? BNE DMOFF ;IF NE NO, TRY OFFSET MOV RKECPS(R2),R1 ;GET ECC ERROR POSITION MOV RKECPT(R2),R3 ;GET ECC CORRECTION PATTERN MOV RKWC(R2),R2 ;GET REMAINING WORD COUNT CALL $ECCOR ;DO THE ECC CORRECTION CALL DMPRM0 ;RESET OFFSET RECOVERY PARAMETERS CALL DMCALC ;RE-CALCULATE DISK ADDRESS MOV #IS.SUC&377,R0 ;ASSUME NO MORE WORDS TO TRANSFER TST U.CNT(R5) ;ANY MORE WORDS TO TRANSFER? BNE 20$ ;IF NE YES CALLR DMFIN ;NO, FINISH I/O 20$: MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS CALL DMCLER ;CLEAR CONTROLLER AND DRIVE CALL DMERL ;FINISH ERROR LOGGING MOV U.BUF+2(R5),RKBA(R2) ;SET PREVIOUS BUFFER ADDRESS MOV I.PRM+10(R1),RKDC(R2) ;SET PREVIOUS CYLINDER ADDRESS MOV I.PRM+12(R1),RKDA(R2) ;SET PREVIOUS DISK ADDRESS CALLR DMDIP ;RESTART THE DATA TRANSFER ; ; **-DMDLT-DATA LATE RECOVERY ; ; THIS ROUTINE IS ENTERED IF A DATA LATE ERROR IS DETECTED. WE WILL NOW ; BACKUP THE WORD COUNT, BUS ADDRESS AND CYLINDER/TRACK/SECTOR ADDDRESS ; BY ONE BLOCK AND RETRY THE TRANSFER FROM THIS POINT. THIS IS DONE TO ; PREVENT THE DATA LATE CONDITION FROM RECURRING DUE TO A LONG TRANSFER. ; ; INPUTS: ; ; R0=IE.VER&377 ; R1=CONTENTS OF RKER ; R2=ADDRESS OF REGISTER SAVE AREA ; DMDLT: MOV S.PKT(R4),R3 ;RETRIEVE I/O PACKET ADDRESS BITB #IQ.X,I.FCN(R3) ;INHIBIT RETRIES BEQ 20$ ;IF EQ NO 10$: JMP DMFIN ;YES, FINISH UP I/O 20$: MOV S.KRB(R4),R3 ;RETRIEVE KRB ADDRESS MOVB K.CON(R3),R3 ;RETRIEVE CONTROLLER INDEX DECB RTTBL(R3) ;ANY RETRIES LEFT? BLE 10$ ;IF LE NO ; FOR WRITE OPERATIONS, RKWC NEEDS TO BE ADJUSTED BY THE NUMBER OF WORDS ; FOUND IN THE SILO. MOV RKWC(R2),R0 ;GET NEGATIVE WORDS REMAINING CMPB #READ+WRT,U.BUF(R5) ; LAST FUNCTION A WRITE? BNE 30$ ;IF NE, ONLY MINOR ADJUSTMENT NECESSARY SUB SILOA(R3),R0 ;ADJUST BY NUMBER OF WORDS FOUND WHEN ;ERROR WAS LOGGED (SEE DMLERR & REGPAS) 30$: SUB #2, R0 ; RKWC CAN STILL BE OFF BY 2 ; FINALLY, CALCULATE WHERE TO RESTART OPERATION ASL R0 ;CONVERT TO NEGATIVE BYTES ADD U.CNT(R5),R0 ;CALCULATE BYTES ACTUALLY TRANSFERED BGE 35$ ;OUT OF BOUNDS DUE TO ADJUSTMENT? CLR R0 ;OK, THEN NO BYTES TRANSFERED 35$: BIC #777,R0 ;GET BLOCKS ACTUALLY TRANSFERED CALL DMCALC ;BACKUP TO START OF BLOCK IN ERROR TST U.CNT(R5) ;LAST BLOCK TRANSFERED? BNE 40$ ;IF NE NO ADD R0,U.CNT(R5) ;YES, NORMALIZE BYTE COUNT 40$: MOV #IE.VER&377,R0 ;ASSUME NO FURTHER RETRIES JMP DMREST ;RESTART THE I/O OPERATION ; ; **-DMOFF-ATTEMPT OFFSET RECOVERY ; ; THIS ROUTINE IS CALLED WHENEVER WE NEED TO OFFSET THE HEADS ; SOME DISTANCE FROM TRACK CENTERLINE TO PROPERLY READ THE DATA. ; ; INPUTS: ; ; R0=NUMBER OF BYTES ACTUALLY TRANSFERED TO THIS POINT ; R3=CONTROLLER INDEX ; DMOFF: DECB OFFRTY(R3) ;ANY RETRIES LEFT? BGT 10$ ;IF GT YES 5$: MOV #IE.VER&377,R0 ;SET UNRECOVERABLE ERROR CALLR DMFIN ;FINISH I/O 10$: MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS TST R0 ;ANY GOOD SECTORS TRANSFERED? BEQ 40$ ;IF EQ NO ; ; THE TRANSFER ENDED IN AN ECC HARD ERROR BUT THERE WERE SECTORS ; TRANSFERED THAT CONTAINED GOOD DATA. SINCE THE ECC HARD ERROR ; COULD HAVE BEEN CAUSED BY A CYLINDER CROSSING, THE GOOD DATA IS ; SAVED AND THE TRANSFER IS RETRIED FROM THE POINT OF ERROR. ; BIT #ECH,RKER(R2) ;WAS IT A HARD ECC ERROR? BEQ 15$ ;IF EQ NO SUB #512.,R0 ;BACK UP TO START OF BLOCK IN ERROR 15$: CALL DMCALC ;RE-CALCULATE DISK ADDRESS TST U.CNT(R5) ;ANY BYTES REMAIN TO BE TRANSFERED? BNE 20$ ;IF NE YES ADD R0,U.CNT(R5) ;NO, NORMALIZE BYTES REMAINING 20$: CALL DMPRM1 ;RESET OFFSET TABLE ADDRESS POINTER BR 50$ ; ; NO GOOD DATA WAS TRANSFERED SO CHECK TO SEE IF THE OFFSET ; FROM TRACK CENTERLINE SHOULD BE CHANGED. ; 40$: DECB OFFRTY+1(R3) ;CHANGE OFFSET? BLE 45$ ;IF LE YES JMP DMINIO ;RESTART THE OPERATION 45$: MOVB #OFFTRY,OFFRTY+1(R3) ;SET RECOVERY RETRY COUNT 50$: INC OFFAD(R3) ;UPDATE OFFSET POINTER MOV @S.KRB(R4),R2 ;RETRIEVE CSR ADDRESS CMP #OFFTBE,OFFAD(R3) ;ALL OFFSETS TRIED? BLT 5$ ;IF YES RETURN ERROR MOVB @OFFAD(R3),R0 ;GET NEXT OFFSET VALUE BNE 60$ ;IF NE NOT RETURNING TO CENTERLINE MOVB #RETRY*2,OFFRTY+1(R3) ;TRY 16 TIMES AT CENTERLINE 60$: CALL DMCLER ;CLEAR CONTROLLER AND DRIVE BIC #^C<377>,R0 ;ISOLATE OFFSET BITS MOV R0,RKOF(R2) ;LOAD NEXT OFFSET VALUE MOV #OFF,R0 ;SET OFFSET FUNCTION BISB #OFS!OFM,U.CW2+1(R5) ;INDICATE OFFSET FUNCTION CALLR DMDIP1 ;EXECUTE OFFSET FUNCTION ; ; RESET THE OFFSET RECOVERY PARAMETERS ; DMPRM: MOV #RETRY,RTTBL(R3);SET INITIAL RETRY COUNT DMPRM0: MOVB #1,OFFRTY+1(R3) ;SET INITIAL RECOVERY COUNT TO ONE MOVB #RETRY*2+OFFTRY*7+16.,OFFRTY(R3) ;SET TOTAL RETRY COUNT ;FOR OFFSET RECOVERY DMPRM1: MOV #OFFTB-1,OFFAD(R3) ;SET OFFSET TABLE POINTER RETURN ; ; ; **-DMERL-FINISH ERROR LOGGING FOR MID TRANSFER ERROR ; ; THIS ROUTINE IS CALLED TO FINISH OFF THE ERROR LOGGING PROCESS ; DURING MID-TRANSFER IF WE HAVE SUCCESSFULLY RECOVERED. ; ; INPUTS: ; ; R3=CONTROLLER INDEX ; DMERL: MOV R2,-(SP) ;SAVE REGISTERS MOV R1,-(SP) ;... MOVB RTTBL(R3),R2 ;GET FINAL ERROR RETRY COUNT BIS #RETRY*256.,R2 ;MERGE STARTING RETRY COUNT MOV #IS.SUC&377,R0 ;RECOVERY WAS SUCCESSFUL CALL $FNERL ;FINISH ERROR LOGGING PROCESS MOV (SP)+,R1 ;RESTORE REGISTERS MOV (SP)+,R2 ;... BR DMPRM ;RESET RECOVERY PARAMETERS AND EXIT ; ; **-DMCALC-CALCULATE UPDATED DISK AND BUFFER ADDRESS ; ; THIS ROUTINE WILL CALCULATE THE NEW DISK AND BUFFER ADDRESSES ; BASED ON THE NUMBER OF BYTES ACTUALLY TRANSFERED. ; ; INPUTS: ; ; R0=BYTES ACTUALLY TRANSFERED ; ; OUTPUTS: ; ; R0=UNCHANGED IF U.CNT(R5)=0 ; I.PRM+10(R1)=NEW CYLINDER ADDRESS ; I.PRM+12(R1)=NEW TRACK/SECTOR ADDRESS ; U.BUF+1(R5)=NEW ADDRESS EXTENSION BITS ; U.BUF+2(R5)=NEW BUS ADDRESS ; DMCALC: SUB R0,U.CNT(R5) ;REDUCE BYTES REMAINING TO TRANSFER BEQ 30$ ;IF EQ NONE LEFT ADD R0,U.BUF+2(R5) ;UPDATE STARTING BUFFER ADDRESS ADCB U.BUF+1(R5) ;PROPAGATE CARRY INTO EXTENSION BITS MOV S.KRB(R4),R1 ;RETREIVE KRB ADDRESS ADD K.OFF(R1),R1 ;POINT TO UMR AREA+2 ADD R0,-(R1) ;CALCULATE NEW REAL ADDRESS ADCB -(R1) ;... 5$: SWAB R0 ;CALCULATE THE NUMBER OF ... ASR R0 ;... SECTORS TRANSFERED MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS ADD I.PRM+12(R1),R0 ;UPDATE TRACK/SECTOR ADDRESS 10$: CMPB #22.,R0 ;SECTOR OVERFLOW? BHI 20$ ;IF HI NO SUB #22.,R0 ;NORMALIZE SECTOR ADDRESS ADD #400,R0 ;ADD IN A TRACK CMP #3*400,R0 ;TRACK OVERFLOW? BHI 10$ ;IF HI NO SUB #3*400,R0 ;NORMALIZE TRACK ADDRESS INC I.PRM+10(R1) ;UPDATE CYLINDER ADDRESS BR 10$ ; 20$: MOV R0,I.PRM+12(R1) ;SAVE UPDATED TRACK/SECTOR ADDRESS 30$: RETURN ; ; ; **-DMVV-PROCESS VOLUME VALID FUNCTIONS ; ; HERE WE WILL PROCESS VOLUME VALID FUNCTIONS. IF THE FUNCTION IS ; RESET VOLUME VALID WE WILL FORCE AN UNLOAD OF THE DRIVE. IF THE ; FUNCTION IS SET VOLUME VALID, WE WILL SET THE HARDWARE "VV" BIT. ; IF THE FUNCTION IS A VOLUME VALID NOP, WE WILL SIZE THE DISK BY ; PASSING THE CONTROLLER REGISTERS BACK TO THE CALLER. ; DMVV: CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV @S.KRB(R4),R2 ;RETREIVE CSR ADDRESS CALL DMCLR ;CLEAR CONTROLLER AND SELECT UNIT CALL DMSDC ;SELECT THE DRIVE CALL DMDC ;CLEAR THE DRIVE MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS TST I.PRM+2(R1) ;SIZE THE DISK? BPL 10$ ;IF PL NO BIT #NED,RKCS2(R2) ;DOES THE DRIVE EXIST? BEQ 5$ ;IF EQ YES CALL DMCLR ;CLEAR THE CONTROLLER MOV #IE.SZE&377,R0 ;UNABLE TO SIZE DEVICE BICB #US.VV,U.STS(R5);RESET VOLUME VALID CALLR DMFIN3 ;EXIT 5$: CALL DMRPAS ;PASS CONTROLLER REGISTERS TO CALLER BR 30$ ; 10$: BIT #VV$SET,I.PRM+2(R1) ;SET VOLUME VALID? BEQ 40$ ;IF EQ NO MOV RKDS(R2),R1 ;GET CONTENTS OF DRIVE STATUS REGISTER COM R1 ;TOGGLE THEM BIT #SVAL!DRDY!DRA,R1 ;DRIVE READY AND ONLINE? BEQ 15$ ;IF EQ YES MOV #IE.DNR&377,R0 ;SET DRIVE NOT READY BICB #US.VV,U.STS(R5);RESET VOLUME VALID BR 35$ ; 15$: MOV #ACK,R0 ;GET PACK ACK FUNCTION CODE 20$: CALL DMGO ;ISSUE THE FUNCTION 30$: MOV #IS.SUC&377,R0 ;SET SUCCESSFUL FUNCTION 35$: CALLR DMFIN1 ;AND EXIT 40$: BIT #VV$UNL,I.PRM+2(R1) ;UNLOAD THE HEADS? BEQ 30$ ;IF EQ NO BIT #PIP,RKDS(R2) ;POSITIONING IN PROGRESS? BNE 30$ ;IF NE YES, IT'S PROBABLY UNLOADING MOV #UNL,R0 ;GET UNLOAD HEADS FUNCTION CODE BR 20$ ; ;+ ; INITIATE A CONTROLLER/DRIVE CLEAR OR SELECT DRIVE FUNCTION ; AND WAIT FOR THE SERIAL MESSAGE. ; ; NOTE: THE TIMING LOOP AT 20$ IS TO ALLOW TIME FOR THE ; SERIAL MESSAGE TO BE SENT TO THE DRIVE AND THE STATUS ; TO BE RECEIVED BY THE RK611. AVERAGE TIME = 15US. ;- .ENABL LSB DMCLER: CALL DMCLR ;CLEAR CONTROLLER DMDC: MOV R0,-(SP) ;SAVE REGISTER MOV #DC,R0 ;GET CODE FOR DRIVE CLEAR BR 10$ ; DMSDC: CLR RKDC(R2) ;CLEAR DESIRED CYLINDER ADDRESS DMSD: MOV R0,-(SP) ; MOV #SD,R0 ;GET CODE FOR SELECT DRIVE 10$: CALL DMGO ;ISSUE THE FUNCTION MOV (SP)+,R0 ; RETURN DMGO: CALL DMXCT ;LOAD RKCS1 20$: TSTB (R2) ;WAIT FOR THE SERIAL MESSAGE ... BPL 20$ ;... TO DO ITS THING RETURN ; DMCLR: MOV #CERR,(R2) ;CLEAR CONTROLLER MOVB U.UNIT(R5),-(SP) ;GET CURRENT UNIT NUMBER MOV (SP)+,RKCS2(R2) ;RE-SELECT THE UNIT RETURN DMXCT: CMP #815.,U.PRM+2(R5) ;IS THIS AN RK07? BNE 30$ ;IF NE NO BIS #CDT,R0 ;YES, SET CONTROLLER DRIVE TYPE BIT 30$: MOV R0,(R2) ;EXECUTE THE FUNCTION RETURN ; DMCYL: MOV #2,RKMR1(R2) ;SET MESSAGE SELECT CODE CALL DMSD ;SELECT DRIVE TO GET MESSAGE MOV RKMR3(R2),R0 ;GET MESSAGE CONTENTS ASH #-4,R0 ;RIGHT JUSTIFY CYLINDER ADDRESS BIC #^C<1777>,R0 ;ISOLATE CURRENT CYLINDER ADDRESS RETURN ; .DSABL LSB ;+ ; **-DMLXXX-RK611-RK06/RK07 DISK CARTRIDGE CONTROLLER ; ERROR LOGGING ROUTINES ; ; THIS ROUTINE IS CALLED WHENEVER A DEVICE ERROR OR DEVICE TIMEOUT ; OCCURS. A CORE BLOCK THE SIZE OF THE REGISTER BUFFER IS ; ALLOCATED AND THE REGISTERS (INCLUDING THE SIX EXTRA MAINTENANCE ; REGISTERS) ARE TRANSFERED INTO THE CORE BLOCK AND THEN THE ; APPROPRIATE EXECUTIVE ERROR LOGGING ROUTINE IS CALLED. THE CORE ; BLOCK ADDRESS IS THEN USED AS A PSEUDO REGISTER BASE ADDRESS BY ; THE ERROR HANDLING ROUTINES. BEFORE THE NEXT FUNCTION IS ISSUED, ; THE REAL CSR ADDRESS MUST BE RESTORED. ; ; NOTE: IF ENTRY IS THE RESULT OF A DEVICE TIMEOUT THEN THIS ; ROUTINE IS EXECUTED AT THE RK611 DEVICE PRIORITY LEVEL (PR5) ; UNTIL THE EXEC ERROR LOGGING ROUTINE IS CALLED. ; ; INPUTS: ; R2 = CSR ADDRESS ; R4 = SCB ADDRESS ; ; OUTPUTS: ; R2 = ADDRESS OF REGISTER SAVE AREA ; R4 = SCB ADDRESS ; ; R0,R3 ARE PRESERVED ACROSS CALL ;- .ENABL LSB DMLTMO: MOV #$DVTMO,R1 ;;;GET ADDRESS OF OVERLAPPED TIMEOUT BR 10$ ;;; DMLERR: MOV #$DVERR,R1 ;GET ADDRESS OF DEVICE ERROR ROUTINE 10$: MOV R3,-(SP) ;SAVE REGISTERS MOV R0,-(SP) ;... MOV R1,-(SP) ;SAVE CO-ROUTINE ADDRESS MOV S.KRB(R4),R3 ;GET CURRENT KRB ADDRESS MOVB K.CON(R3),R3 ;RETRIEVE CONTROLLER INDEX MUL #RMCNT,R3 ;FORM AN INDEX INTO ... ADD #RGBLK,R3 ;... REGISTER BLOCK AREA MOV R3,R0 ;COPY REGISTER ADDRESS MOV R0,-(SP) ;SAVE THIS FOR LATER CALL REGPAS ;FILL AREA WITH REGISTERS MOV (SP)+,R2 ;RETRIEVE REGISTER AREA ADDRESS CALL @(SP)+ ;CALL EXEC ERROR LOGGING ROUTINE MOV (SP)+,R0 ;RESTORE REGISTERS MOV (SP)+,R3 ;... RETURN ; .DSABL LSB ;+ ; **-DMRPAS-RK611-RK06/RK07 DISK CARTRIDGE CONTROLLER ; CONTROLLER REGISTER PASS ROUTINE ; ; THIS ROUTINE WILL TRANSFER THE CONTENTS OF THE CONTROLLER ; REGISTERS (INCLUDING THE SIX EXTRA MAINTENANCE REGISTERS) ; INTO A PREVIOUSLY ALLOCATED BUFFER. ; ; INPUTS: ; R0 = BUFFER ADDRESS ; R1 = I/O PACKET ADDRESS ; R2 = CSR ADDRESS ; R4 = SCB ADDRESS ; R5 = UCB ADDRESS ; OUTPUTS: ; R2 = CSR ADDRESS ; R3 = DESTROYED ;- DMRPAS: MOV I.PRM+14(R1),KISAR6 ;SET BUFFER RELOCATION BIAS MOV I.PRM+16(R1),R0 ;GET REGISTER BUFFER ADDRESS REGPAS: MOV #RKMR2/2,R3 ;NUMBER OF MAJOR REGISTERS TO PASS MOV R2,-(SP) ;SAVE CSR ADDRESS 10$: MOV (R2)+,(R0)+ ;TRANSFER THE REGISTER SOB R3,10$ ;LOOP UNTIL ALL ARE TRANSFERED MOV (SP)+,R2 ;RESTORE CSR ADDRESS MOV R0,R3 ;SAVE BUFFER POSITION ; DETERMINE NUMBER OF WORDS CONTAINED IN SILO MOV S.KRB(R4),R0 ;RETRIEVE KRB ADDRESS MOVB K.CON(R0),R0 ;PICK UP CONTROLLER INDEX CLR SILOA(R0) ;ASSUME NO ADJUSTMENT BIT #OR,RKCS2-RKMR2(R3) ; WAS DATA AVAILABLE? BEQ 17$ ;IF EQ- NO ADJUSTMENT WAS NEEDED INC SILOA(R0) ;COUNT RKDB ALREADY STORED 12$: BIT #OR,RKCS2(R2) ;CHECK REAL CSR FOR ANY REMAINING BEQ 17$ ;IF EQ, NO- SILO EMPTY TST RKDB(R2) ;POP ANOTHER WORD INC SILOA(R0) ;COUNT RKDB ALREADY STORED BR 12$ ;UNTIL EMPTY! 17$: CALL DMCLR ;CLEAR CONTROLLER ERRORS CALL DMCYL ;GET CURRENT CYLINDER ADDRESS MOV R0,RKDC-RKMR2(R3) ;STORE CURRENT CYLINDER ADDRESS MOV R3,R0 ;RESTORE BUFFER POINTER CLR R3 ;CLEAR COUNT 20$: CALL DMCLR ;CLEAR CONTROLLER MOV R3,RKMR1(R2) ;SELECT DRIVE SERIAL MESSAGE CALL DMSD ;SELECT DRIVE TO GET PROPER MESSAGE MOV RKMR2(R2),(R0)+ ;SAVE CONTENTS OF MR2 MOV RKMR3(R2),(R0)+ ;SAVE CONTENTS OF MR3 INC R3 ;INCREMENT DRIVE SERIAL MESSAGE COUNT CMP R3,#4 ;DONE FOUR MESSAGES YET? BNE 20$ ;NO, LOOP CALLR DMCLER ;CLEAR CONTROLLER AND DRIVE AND EXIT ;+ ; **-DMDINT-RK611-RK06/RK07 DISK CARTRIDGE CONTROLLER ; DIAGNOSTIC INTERRUPT HANDLER ; ; THIS SUBROUTINE HANDLES INTERUPTS FROM DIAGNOSTIC OPERATIONS. ; IF THE FUNCTION WAS DIAGNOSTIC THEN THE DEVICE REGISTERS ; ARE PASSED BACK TO THE DIAGNOSTIC TASK, THE CONTROLLER (VIA DMRPAS) ; AND THE DRIVE ARE CLEARED AND THE I/O STATUS IS RETURNED. ; ; INPUTS: ; R0 = I/O STATUS CODE ; R1 = ADDRESS OF I/O PACKET ; R2 = ADDRESS OF CSR ; R4 = ADDRESS OF SCB ; R5 = ADDRESS OF UCB ; ; OUTPUTS: ; R1 = I/O PACKET ADDRESS (IF DIAGNOSTIC FUNCTION) ; R2 = ADDRESS OF CSR ; R4 = ADDRESS OF SCB ; C = 1 IF INTERRUPT WAS FROM DIAGNOSTIC FUNCTION ; ; R0,R3 ARE PRESERVED ACROSS CALL ;- DMDINT: CLC ;ASSUME NOT DIAGNOSTIC INTERRUPT BITB #IQ.UMD,I.FCN(R1) ;DIAGNOSTIC FUNCTION? BEQ 30$ ;IF EQ NO, EXIT MOV R3,-(SP) ;SAVE REGISTER MOV R1,R3 ;COPY I/O PACKET ADDRESS MOV R0,-(SP) ;SAVE CURRENT I/O STATUS CODE TSTB R0 ;WAS THIS A SUCCESSFUL INTERRUPT? BMI 20$ ;IF MI JUST PASS THE REGISTERS CMP #IO.RDH!IQ.UMD,I.FCN(R3) ;READ HEADERS? BNE 20$ ;NO, PROCESS NORMAL CLR R0 ;CLEAR BYTE OFFSET INTO BUFFER CALL $RELOP ;RELOCATE PHYSICAL ADDRESS MOV RKDB(R2),(R1)+ ;TRANSFER FIRST HEADER WORD MOV RKDB(R2),(R1)+ ;TRANSFER SECOND HEADER WORD MOV RKDB(R2),(R1)+ ;TRANSFER THIRD HEADER WORD 20$: CALL DMSDC ;SELECT THE DRIVE MOV R3,R1 ;SAVE I/O PACKET ADDRESS CALL DMRPAS ;PASS THE CONTROLLER REGISTERS SEC ;SET DIAGNOSTIC INTERRUPT RETURN MOV (SP)+,R0 ;RESTORE I/O STATUS CODE MOV (SP)+,R3 ;RESTORE CONTROLLER INDEX 30$: RETURN ;+ ; **-DMCKB-VALIDATE AND CONVERT THE LBN ; ; THIS ROUTINE IS CALLED FROM $DRQRQ TO DO LBN PROCESSING ; FOR DEVICES WHICH SUPPORT QUEUE OPTIMIZATION. IF BLKC2 ; DETECTS AN ERROR IT WILL RETURN TO THE CORRECT PLACE IN ; $DRQRQ AFTER CALLING $IOALT. ; ; INPUTS: ; ; R1=I/O PACKET ADDRESS ; R5=UCB ADDRESS ; ; OUTPUTS: ; ; IF THE CHECKS SUCCEEDS, THEN THE LBN IN THE PACKET ; IS REPLACED BY THE CYLINDER/TRACK/SECTOR. R1 IS PRESERVED. ; ; IF THE CHECKS FAILS, THEN $IOALT IS ENTERED WITH A FINAL ; STATUS OF IE.BLK AND A RETURN TO THE CORRECT PLACE IN ; $DRQRQ IS EXECUTED. ; ; ; NOTE: ALL FUNCTIONS PUT INTO THE DRIVER QUEUE ARRIVE HERE. ; THESE INCLUDE IO.ATT, IO.DET, AND ACP FUNCTIONS. ;- DMCHK: MOV I.FCN(R1),-(SP) ;PUT THE FUNCTION ONTO THE STACK CMPB #IO.ATT/256.,1(SP) ;IS IT ATTACH BEQ 35$ ;IF EQ YES - LEAVE IT ALONE CMPB #IO.DET/256.,1(SP) ;IS IT DETACH BEQ 35$ ;IF EQ YES - LEAVE IT ALONE BIC #7,(SP) ;CLEAR THE SUBFUNCTION BITS CMP #IO.STC,(SP) ;IS IT SET CHARACTERISTICS? BEQ 35$ ;IF EQ YES - LEAVE IT ALONE TST (SP)+ ;CLEAN THE STACK CALL $BLKC2 ;CHECK LOGICAL BLOCK NUMBER CMPB #IO.WLB/256.,I.FCN+1(R3) ;WRITE FUNCTION? BNE 20$ ;IF NE NO BITB #IO.WLT&377,I.FCN(R3) ;OK TO WRITE ON LAST TRACK? BNE 20$ ;IF NE YES MOV R0,I.PRM+6(R3) ;SAVE STARTING BLOCK NUMBER ADD #22.,I.PRM+12(R3) ;ADD 1 TRACK'S WORTH OF BLOCKS MOV R3,R1 ;RESTORE PACKET ADDRESS FOR THE CALL CALL $BLKC2 ;CHECK IF WRITE ON LAST TRACK OF DISK MOV I.PRM+6(R3),R0 ;RESTORE ORIGINAL STARTING BLOCK NUMBER 20$: CALL $CVLBN ;CONVERT LOGICAL BLOCK NUMBER MOV R2,I.PRM+10(R3) ;SAVE DESIRED CYLINDER ADDRESS SWAB R1 ;SWAP TRACK TO HIGH BYTE BIS R1,R0 ;MERGE TRACK WITH SECTOR MOV R0,I.PRM+12(R3) ;SAVE DESIRED TRACK AND SECTOR ADDRESS MOV R3,R1 ;RESTORE THE PACKET ADDRESS 30$: RETURN ;EXIT 35$: TST (SP)+ ;CLEAN THE STACK BR 30$ ;AND EXIT .END